//
// Created by songpingwang on 25-7-13.
//

#ifndef UDATAVIEW_H
#define UDATAVIEW_H


#include "UDataBase.h"


namespace NDFrame {
    class UDataFrame;
    class UDataView final : public UDataBase {
        using VecItemPtr = std::vector<DataItem *>;
        size_t m_size;
        DataItem *m_dataPtr;

    public:
        explicit UDataView(const UDataFrame &dataFrame) : m_size(dataFrame.size()), m_dataPtr(dataFrame.getItemPtr()) {}

        UDataView(const UDataFrame &dataFrame, const size_t idx0, const size_t idx1)
        : m_size(idx1 - idx0),
        m_dataPtr(dataFrame.getItemPtr() + idx0) {
            if (idx0 >= dataFrame.size() || idx1 > dataFrame.size() || idx0 > idx1) {
                throw std::out_of_range("View range out of bounds");
            }
        }

        UDataView(const UDataView &dataview, const size_t idx0, const size_t idx1)
        : m_size(idx1 - idx0),
        m_dataPtr(dataview.getItemPtr() + idx0) {
            if (idx0 >= dataview.size() || idx1 > dataview.size() || idx0 > idx1) {
                throw std::out_of_range("View range out of bounds");
            }
        }

        // 移动构造函数
        UDataView(UDataView&& other) noexcept : m_size(other.m_size), m_dataPtr(other.m_dataPtr) {
            other.m_size = 0;
            other.m_dataPtr = nullptr;
        }

        // 移动赋值运算符
        UDataView& operator=(UDataView&& other) noexcept {
            if (this != &other) {
                m_size = other.m_size;
                m_dataPtr = other.m_dataPtr;
                other.m_size = 0;
                other.m_dataPtr = nullptr;
            }
            return *this;
        }

        DataItem &back() override {
            if (m_size == 0) {
                throw std::out_of_range("UDataView is empty");
            }
            return m_dataPtr[m_size - 1];
        }

        DataItem &front() override {
            if (m_size == 0) {
                throw std::out_of_range("UDataView is empty");
            }
            return m_dataPtr[0];
        }

        [[nodiscard]] size_t size() const override { return m_size; }

        [[nodiscard]] DataItem *getItemPtr() const override { return m_dataPtr; }

        [[nodiscard]] bool empty() const override { return m_size == 0; }

        VOID_USE void print() const override {
            format_print(*this);
        }

        const DataItem &operator[](const size_t index) const {
            if (index >= m_size) {
                throw std::out_of_range("Index out of range");
            }
            return m_dataPtr[index];
        }


        /*
        *   判断ZDataFrame的text字段是否在field字符串集合中
        *   - 返回值：
        *     std::vector<size_t>& indices     返回符合条件的索引
        *     VecItemPtr& pointers 返回符合条件的ZDataFrame的行指针
        *     ZDataFrame& dataframe            返回符合条件的ZDataFrame(深复制)
        */
        template<Field field>
        bool is_in(const std::vector<std::string> &txts, VecItemPtr &out_pointers) const;

        /*
        * 仿照python的join函数
        * 默认为空字符串
        * join_replace对ZDataFrame的text合并后的字符串中的字符进行替换
        * const std::string& Char_为分隔符
        */
        template<Field field>
        MAYBE_USE std::string join(std::string_view separator) const;

        template<Field field>
        MAYBE_USE std::string join_and_replace(
            char oldChar,
            std::string_view newChars,
            std::string_view separator = "") const;


        template<typename Predicate>
        MAYBE_USE bool filter(VecItemPtr& out_pointers, Predicate predicate) const;

        template<typename Predicate>
        UDataFrame DF_filter(Predicate predicate) const;


        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex() const {
            return DF_reg_impl_v<field, patterns...>();
        }

        //////////////////////////////////////////////
        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_strlen_grate(const int len) const {
            return DF_reg_len_cmp_v<field, patterns...>(len, std::greater<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_strlen_equal(const int len) const {
            return DF_reg_len_cmp_v<field, patterns...>(len, std::equal_to<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_strlen_less(const int len) const {
            return DF_reg_len_cmp_v<field, patterns...>(len, std::less<>());
        }

        ////////////////////////////////////////////////////////////
        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame
        DF_loc_regex_xyxy(int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const DataItem &item) {
                return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 && item.y1 < y1;
            };
            return DF_reg_cond_v<field, patterns...>(condition);
        }

        ////////////////////////////////////////////////////////////
        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_x0x1(int x0, int x1) const {
            return DF_reg_cond_v<field, patterns...>(
                                  [x0, x1](const DataItem &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_y0y1(int y0, int y1) const {
            return DF_reg_cond_v<field, patterns...>(
                                  [y0, y1](const DataItem &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_x0y0_grate(int x0, int y0) const {
            return DF_reg_cond_v<field, patterns...>(
                                  [x0, y0](const DataItem &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_loc_regex_x1y1_less(int x1, int y1) const {
            return DF_reg_cond_v<field, patterns...>(
                                  [x1, y1](const DataItem &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        MAYBE_USE UDataFrame DF_loc_xyxy(int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const DataItem &item) -> bool {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            };
            return DF_xyxy_impl_v(condition);
        }

        MAYBE_USE UDataFrame DF_loc_x0x1(int x0, int x1) const {
            return DF_xyxy_impl_v([x0, x1](const DataItem &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE UDataFrame DF_loc_y0y1(int y0, int y1) const {
            return DF_xyxy_impl_v([y0, y1](const DataItem &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE UDataFrame DF_loc_x0y0_grate(int x0, int y0) const {
            return DF_xyxy_impl_v([x0, y0](const DataItem &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE UDataFrame DF_loc_x1y1_less(int x1, int y1) const {
            return DF_xyxy_impl_v([x1, y1](const DataItem &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        MAYBE_USE UDataFrame DF_loc_x1y1_grate(int x1, int y1) const {
            return DF_xyxy_impl_v([x1, y1](const DataItem &item) { return item.x1 > x1 && item.y1 > y1; });
        }

        MAYBE_USE UDataFrame DF_loc_x0_grate(int x0) const {
            return DF_xyxy_impl_v([x0](const DataItem &item) { return item.x0 > x0; });
        }

        MAYBE_USE UDataFrame DF_loc_y0_grate(int y0) const {
            return DF_xyxy_impl_v([y0](const DataItem &item) { return item.y0 > y0; });
        }

        MAYBE_USE UDataFrame DF_loc_x0_less(int x0) const {
            return DF_xyxy_impl_v([x0](const DataItem &item) { return item.x0 < x0; });
        }

        MAYBE_USE UDataFrame DF_loc_y0_less(int y0) const {
            return DF_xyxy_impl_v([y0](const DataItem &item) { return item.y0 < y0; });
        }

        MAYBE_USE UDataFrame DF_loc_x1_less(int x1) const {
            return DF_xyxy_impl_v([x1](const DataItem &item) { return item.x1 < x1; });
        }

        MAYBE_USE UDataFrame DF_loc_y1_less(int y1) const {
            return DF_xyxy_impl_v([y1](const DataItem &item) { return item.y1 < y1; });
        }

        MAYBE_USE UDataFrame DF_loc_x1_grate(int x1) const {
            return DF_xyxy_impl_v([x1](const DataItem &item) { return item.x1 > x1; });
        }

        MAYBE_USE UDataFrame DF_loc_y1_grate(int y1) const {
            return DF_xyxy_impl_v([y1](const DataItem &item) { return item.y1 > y1; });
        }


        /*
         * 对视图类再次筛选，函数功能与ZDataFrame一样
         * 对UDataView进行再次过滤（具体过滤函数：传入Field：（TEXT,TEXT_SEP）, 以及筛选条件） 返回符合条件的地址
         * loc_regex             返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】
         * loc_[regex,_xyxy]     返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】,筛选条件[regex, (>x0,y0; <x1,y1)]
         * loc_[regex,_x0x1]     返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】,筛选条件[regex, (>x0; <x1)]
         * loc_[regex,_y0y1]     返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】,筛选条件[regex, (>y0; <y1)]
         * loc_[regex,_x0y0]     返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】,筛选条件[regex, (<x0; <y0)]
         * loc_[regex,_x1y1]     返回查找值是否为空, 第一个参数为筛选输出【DataItem的地址】,筛选条件[regex, (>x1; >y1)]
         */

        template<Field field, auto... patterns>
        MAYBE_USE bool loc_regex(VecItemPtr &out_ptr) const {
            return ptr_reg_impl_v<field, patterns...>(out_ptr);
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_strlen_grate(VecItemPtr &out_ptr, const int len) const {
            return ptr_reg_len_cond_v<field, patterns...>(out_ptr, len, std::greater<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_strlen_equal(VecItemPtr &out_ptr, const int len) const {
            return ptr_reg_len_cond_v<field, patterns...>(out_ptr, len, std::equal_to<>());
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_strlen_less(VecItemPtr &out_ptr, const int len) const {
            return ptr_reg_len_cond_v<field, patterns...>(out_ptr, len, std::less<>());
        }


        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_xyxy(VecItemPtr &out_ptr, int x0, int y0, int x1, int y1) const {
            return ptr_reg_cond_v<field, patterns...>(out_ptr,
                                                      [x0, y0, x1, y1](const DataItem &item) {
                                                          return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 && item.y1
                                                                 < y1;
                                                      });
        }


        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_x0x1(VecItemPtr &out_ptr, int x0, int x1) const {
            return ptr_reg_cond_v<field, patterns...>(out_ptr,
                                                      [x0, x1](const DataItem &item) {
                                                          return item.x0 > x0 && item.x1 < x1;
                                                      });
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_y0y1(VecItemPtr &out_ptr, int y0, int y1) const {
            return ptr_reg_cond_v<field, patterns...>(out_ptr,
                                                      [y0, y1](const DataItem &item) {
                                                          return item.y0 > y0 && item.y1 < y1;
                                                      });
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_x0y0(VecItemPtr &out_ptr, int x0, int y0) const {
            return ptr_reg_cond_v<field, patterns...>(out_ptr,
                                                      [x0, y0](const DataItem &item) {
                                                          return item.x0 > x0 && item.y0 > y0;
                                                      });
        }

        template<Field field, auto... patterns>
        MAYBE_USE bool
        loc_regex_x1y1(VecItemPtr &out_ptr, int x1, int y1) const {
            return ptr_reg_cond_v<field, patterns...>(out_ptr,
                                                      [x1, y1](const DataItem &item) {
                                                          return item.x1 < x1 && item.y1 < y1;
                                                      });
        }


        MAYBE_USE bool loc_xyxy(VecItemPtr &out_ptr, int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const DataItem &item) {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            };
            return ptr_xyxy(out_ptr, condition);
        }

        MAYBE_USE bool loc_x0x1(VecItemPtr &out_ptr, int x0, int x1) const {
            return ptr_xyxy(out_ptr, [x0, x1](const DataItem &item) {
                return item.x0 > x0 && item.x1 < x1;
            });
        }

        MAYBE_USE bool loc_y0y1(VecItemPtr &out_ptr, int y0, int y1) const {
            return ptr_xyxy(out_ptr, [y0, y1](const DataItem &item) {
                return item.y0 > y0 && item.y1 < y1;
            });
        }

        MAYBE_USE bool loc_x0y0(VecItemPtr &out_ptr, int x0, int y0) const {
            return ptr_xyxy(out_ptr, [x0, y0](const DataItem &item) {
                return item.x0 > x0 && item.y0 > y0;
            });
        }

        MAYBE_USE bool loc_x1y1(VecItemPtr &out_ptr, int x1, int y1) const {
            return ptr_xyxy(out_ptr, [x1, y1](const DataItem &item) {
                return item.x1 < x1 && item.y1 < y1;
            });
        }

        MAYBE_USE bool loc_x0(VecItemPtr &out_ptr, int x0) const {
            return ptr_xyxy(out_ptr, [x0](const DataItem &item) { return item.x0 < x0; });
        }

        MAYBE_USE bool loc_y0(VecItemPtr &out_ptr, int y0) const {
            return ptr_xyxy(out_ptr, [y0](const DataItem &item) { return item.y0 < y0; });
        }

        MAYBE_USE bool loc_x1(VecItemPtr &out_ptr, int x1) const {
            return ptr_xyxy(out_ptr, [x1](const DataItem &item) { return item.x1 > x1; });
        }

        MAYBE_USE bool loc_y1(VecItemPtr &out_ptr, int y1) const {
            return ptr_xyxy(out_ptr, [y1](const DataItem &item) { return item.y1 > y1; });
        }


    private:
        template<Field field, auto... patterns>
        MAYBE_USE UDataFrame DF_reg_impl_v() const;

        template<typename Predicate>
        MAYBE_USE UDataFrame DF_xyxy_impl_v(Predicate predicate) const;

        template<Field field, auto... patterns, typename Comparator>
        MAYBE_USE UDataFrame DF_reg_len_cmp_v(size_t len, Comparator compare) const;

        template<Field field, auto... patterns, typename Predicate>
        MAYBE_USE UDataFrame DF_reg_cond_v(Predicate predicate) const;

        template<Field field, auto... patterns>
        MAYBE_USE bool ptr_reg_impl_v(VecItemPtr &out_ptr) const;

        template<Field field, auto... patterns, typename Predicate>
        MAYBE_USE bool ptr_reg_len_cond_v(VecItemPtr &out_ptr, int len, Predicate predicate) const;

        template<Field field, auto... patterns, typename Predicate>
        MAYBE_USE bool ptr_reg_cond_v(VecItemPtr &out_ptr, Predicate predicate) const;

        template<typename Predicate>
        MAYBE_USE bool ptr_xyxy(VecItemPtr& out_ptr, Predicate predicate) const;
    };
} // NDFrame

#include "UDataView.inl"
#endif //UDATAVIEW_H
